#include "ShadowEffect.h"
#include "Game.h"
#include <assert.h>

void ShadowEffect::Initialize()
{
	mDevice = CDirect3D::Instance()->GetDevice();
	mDeviceContext = CDirect3D::Instance()->GetDeviceContext();

	DWORD shaderFlags = D3D11_CREATE_DEVICE_DEBUG ;


	ID3D10Blob* errorMessage;
	ID3D10Blob* compileShader;
	HRESULT result = D3DX11CompileFromFile(L"Contents\\Shaders\\ShadowEffect.fx", 0, 0, 0, "fx_5_0", shaderFlags, 0, 0, &compileShader, &errorMessage, 0);

	//char* compileErrors = (char*)(errorMessage->GetBufferPointer());

	//assert(!FAILED(result));

	D3DX11CreateEffectFromMemory(compileShader->GetBufferPointer(), compileShader->GetBufferSize(), 0, mDevice, &mEffect);

	mTechnique = mEffect->GetTechniqueByName("ShadowEffect");
	mFxMatrixWorld = mEffect->GetVariableByName("gWorldMatrix")->AsMatrix();
	mFxCameraViewMatrix = mEffect->GetVariableByName("gCameraViewMatrix")->AsMatrix();
	mFxCameraProjectionMatrix = mEffect->GetVariableByName("gCameraProjectionMatrix")->AsMatrix();
	mFxDepthViewMatrix = mEffect->GetVariableByName("gDepthViewMatrix")->AsMatrix();
	mFxDepthProjectionMatrix = mEffect->GetVariableByName("gDepthProjectionMatrix")->AsMatrix();
	mFxDepthLargeViewMatrix = mEffect->GetVariableByName("gDepthLargeViewMatrix")->AsMatrix();
	mFxDepthLargeProjectionMatrix = mEffect->GetVariableByName("gDepthLargeProjectionMatrix")->AsMatrix();

	InitInputLayout();

	D3D11_SAMPLER_DESC samplerDesc;
	samplerDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT;
	samplerDesc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP;
	samplerDesc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP;
	samplerDesc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP;
	samplerDesc.MipLODBias = 0.0f;
	samplerDesc.MaxAnisotropy = 1;
	samplerDesc.ComparisonFunc = D3D11_COMPARISON_ALWAYS;
	samplerDesc.BorderColor[0] = 0;
	samplerDesc.BorderColor[1] = 0;
	samplerDesc.BorderColor[2] = 0;
	samplerDesc.BorderColor[3] = 0;
	samplerDesc.MinLOD = 0;
	samplerDesc.MaxLOD = D3D11_FLOAT32_MAX;
	mDevice->CreateSamplerState(&samplerDesc, &mSampleStateClamp);
}

void ShadowEffect::InitInputLayout()
{
	HRESULT result;
	unsigned int numElements;
	D3D11_INPUT_ELEMENT_DESC polygonLayout[4];

	// Create the vertex input layout description.
	// This setup needs to match the VertexType stucture in the ModelClass and in the shader.
	polygonLayout[0].SemanticName = "POSITION";
	polygonLayout[0].SemanticIndex = 0;
	polygonLayout[0].Format = DXGI_FORMAT_R32G32B32_FLOAT;
	polygonLayout[0].InputSlot = 0;
	polygonLayout[0].AlignedByteOffset = 0;
	polygonLayout[0].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
	polygonLayout[0].InstanceDataStepRate = 0;

	polygonLayout[1].SemanticName = "TEXCOORD";
	polygonLayout[1].SemanticIndex = 0;
	polygonLayout[1].Format = DXGI_FORMAT_R32G32_FLOAT;
	polygonLayout[1].InputSlot = 0;
	polygonLayout[1].AlignedByteOffset = D3D11_APPEND_ALIGNED_ELEMENT;
	polygonLayout[1].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
	polygonLayout[1].InstanceDataStepRate = 0;

	polygonLayout[2].SemanticName = "TEXCOORD";
	polygonLayout[2].SemanticIndex = 1;
	polygonLayout[2].Format = DXGI_FORMAT_R32G32B32_FLOAT;
	polygonLayout[2].InputSlot = 0;
	polygonLayout[2].AlignedByteOffset = D3D11_APPEND_ALIGNED_ELEMENT;
	polygonLayout[2].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
	polygonLayout[2].InstanceDataStepRate = 0;

	polygonLayout[3].SemanticName = "FOG";
	polygonLayout[3].SemanticIndex = 0;
	polygonLayout[3].Format = DXGI_FORMAT_R32_FLOAT;
	polygonLayout[3].InputSlot = 0;
	polygonLayout[3].AlignedByteOffset = D3D11_APPEND_ALIGNED_ELEMENT;
	polygonLayout[3].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
	polygonLayout[3].InstanceDataStepRate = 0;

	numElements = sizeof(polygonLayout) / sizeof(polygonLayout[0]);

	// Create the vertex input layout.
	D3DX11_PASS_SHADER_DESC effectVsDesc;
	mTechnique->GetPassByIndex(0)->GetVertexShaderDesc(&effectVsDesc);
	D3DX11_EFFECT_SHADER_DESC  effectVsDesc2;
	effectVsDesc.pShaderVariable->GetShaderDesc(effectVsDesc.ShaderIndex, &effectVsDesc2);
	const void *vsCodePtr = effectVsDesc2.pBytecode;
	unsigned vsCodeLen = effectVsDesc2.BytecodeLength;

	result = mDevice->CreateInputLayout(polygonLayout, numElements, vsCodePtr, vsCodeLen, &mInputLayout);

	assert(!FAILED(result));


}

void ShadowEffect::Uninit()
{

}

void ShadowEffect::SetDepthTexture(ID3D11ShaderResourceView *pDepthTexture)
{
	mDepthTexture = pDepthTexture;
}

void ShadowEffect::SetDepthLargeTexture(ID3D11ShaderResourceView *pDepthTexture)
{
	mDepthLargeTexture = pDepthTexture;
}

void ShadowEffect::SetTransformsMatrices(const XMFLOAT4X4 &pWorldMatrix, const XMFLOAT4X4 &pCameraViewMatrix, const XMFLOAT4X4 &pCameraProjectionMatrix, const XMFLOAT4X4 &pLightViewMatrix, const XMFLOAT4X4 &pLightProjectionMatrix, const XMFLOAT4X4 &pLightLargeViewMatrix, const XMFLOAT4X4 &pLightLargeProjectionMatrix)
{
	mFxMatrixWorld->SetMatrix(reinterpret_cast<const float*>(&pWorldMatrix));
	mFxCameraViewMatrix->SetMatrix(reinterpret_cast<const float*>(&pCameraViewMatrix));
	mFxCameraProjectionMatrix->SetMatrix(reinterpret_cast<const float*>(&pCameraProjectionMatrix));
	mFxDepthViewMatrix->SetMatrix(reinterpret_cast<const float*>(&pLightViewMatrix));
	mFxDepthProjectionMatrix->SetMatrix(reinterpret_cast<const float*>(&pLightProjectionMatrix));
	mFxDepthLargeViewMatrix->SetMatrix(reinterpret_cast<const float*>(&pLightLargeViewMatrix));
	mFxDepthLargeProjectionMatrix->SetMatrix(reinterpret_cast<const float*>(&pLightLargeProjectionMatrix));
}

void ShadowEffect::Render(int pIndexCount)
{
	mTechnique->GetPassByIndex(0)->Apply(0, mDeviceContext);
	mDeviceContext->PSSetShaderResources(0, 1, &mDepthTexture);
	mDeviceContext->PSSetShaderResources(1, 1, &mDepthLargeTexture);
	mDeviceContext->IASetInputLayout(mInputLayout);	
	mDeviceContext->PSSetSamplers(0, 1, &mSampleStateClamp);
	mDeviceContext->DrawIndexed(pIndexCount, 0, 0);
}

